﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.IO.IsolatedStorage;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Navigation;

namespace CuteRibs.MVVMLib
{
	public static class Extensions
	{
		public static bool Navigate(this NavigationService source, string relativeUri, params object[] parameters)
		{
			var uri = new Uri(string.Format(relativeUri, parameters), UriKind.Relative);
			return source.Navigate(uri);
		}

		public static bool Navigate(this Frame source, string relativeUri, params object[] parameters)
		{
			var uri = new Uri(string.Format(relativeUri, parameters), UriKind.Relative);
			return source.Navigate(uri);
		}

		public static int ParseInt32(this string source)
		{
			int value;
			int.TryParse(source, out value);
			return value;
		}

		public static bool In<T>(this T source, params T[] array)
		{
			return In(source, (IEnumerable<T>)array);
		}

		public static bool In<T>(this T source, IEnumerable<T> array)
		{
			if (array == null)
			{
				throw new ArgumentNullException("array");
			}

			return array.Contains(source);
		}

		public static bool IsBetween<T>(this T source, T tMin, T tMax) where T : IComparable<T>, IEquatable<T>
		{
			return source.CompareTo(tMin) >= 0 && source.CompareTo(tMax) <= 0;
		}

		public static ObservableCollection<T> ToObservableCollection<T>(this IEnumerable<T> collection)
		{
			return new ObservableCollection<T>(collection);
		}

		#region DependencyObject
		public static IEnumerable<DependencyObject> GetDescendants(this DependencyObject source)
		{
			if (source != null)
			{
				for (int i = 0; i < VisualTreeHelper.GetChildrenCount(source); i++)
				{
					var child = VisualTreeHelper.GetChild(source, i);
					yield return child;

					foreach (var descendents in GetDescendants(child))
					{
						yield return descendents;
					}
				}
			}
		}

		public static IEnumerable<T> GetDescendants<T>(this DependencyObject source)
			where T : DependencyObject
		{
			return GetDescendants(source).OfType<T>();
		}

		public static T FindFirstDescendant<T>(this DependencyObject source)
			where T : DependencyObject
		{
			return GetDescendants<T>(source).FirstOrDefault();
		}

		public static T FindDescendant<T>(this DependencyObject source, string name)
			where T : FrameworkElement
		{
			return GetDescendants<T>(source).FirstOrDefault(d => d.Name == name);
		}

		public static IEnumerable<DependencyObject> GetAncestors(this DependencyObject source)
		{
			if (source != null)
			{
				var parent = VisualTreeHelper.GetParent(source);

				if (parent != null)
				{
					foreach (var ancestor in GetAncestors(parent))
					{
						yield return ancestor;
					}

					yield return parent;
				}
			}
		}

		public static IEnumerable<T> GetAncestors<T>(this DependencyObject source)
			where T : DependencyObject
		{
			return GetAncestors(source).OfType<T>();
		}

		public static T FindFirstAncestor<T>(this DependencyObject source)
			where T : DependencyObject
		{
			return GetAncestors<T>(source).FirstOrDefault();
		}

		public static T FindAncestor<T>(this DependencyObject source, string name)
			where T : FrameworkElement
		{
			return GetAncestors<T>(source).FirstOrDefault(d => d.Name == name);
		}

		public static VisualStateGroup FindVisualStateGroup(this FrameworkElement source, string name)
		{
			var vsGroups = VisualStateManager.GetVisualStateGroups(source).OfType<VisualStateGroup>();
			return vsGroups.FirstOrDefault(g => g.Name == name);
		} 
		#endregion

		#region IsolatedStorageFile
		public static void DeleteWholeDirectory(this IsolatedStorageFile source, string path)
		{
			if (source.DirectoryExists(path))
			{
				foreach (var file in source.GetFileNames(Path.Combine(path, "*")))
				{
					source.DeleteFile(Path.Combine(path, file));
				}

				foreach (var directory in source.GetDirectoryNames(Path.Combine(path, "*")))
				{
					DeleteWholeDirectory(source, Path.Combine(path, directory));
				}

				source.DeleteDirectory(path);
			}
		}

		public static void EnsureDirectory(this IsolatedStorageFile source, string path)
		{
			string directory;

			if (path.IndexOf('\\') > -1)
			{
				path = path.Replace('\\', '/');
			}

			for (var i = path.IndexOf('/'); i > -1; i = path.IndexOf('/', i + 1))
			{
				directory = path.Substring(0, i);

				if (!source.DirectoryExists(directory))
				{
					source.CreateDirectory(directory);
				}
			}
		}

		#endregion
	}
}
